home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 September / macformat-004.iso / Shareware City / Games / Jotto ][ 1.1.source Folder / Jotto ][ ƒ / Shell ƒ / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-06  |  18.0 KB  |  701 lines  |  [TEXT/KAHL]

  1. /**********************************************************************\
  2.  
  3. File:        help.c
  4.  
  5. Purpose:    This module handles displaying the different help windows.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program in a file named "GNU General Public License".
  19. If not, write to the Free Software Foundation, 675 Mass Ave,
  20. Cambridge, MA 02139, USA.
  21.  
  22. \**********************************************************************/
  23.  
  24. #include "help.h"
  25. #include "environment.h"
  26. #include "util.h"
  27. #include "buttons.h"
  28. #include "timing.h"
  29. #include "program globals.h"
  30.  
  31. #define DEAD_SPACE_TOP        10
  32. #define DEAD_SPACE_LEFT        10
  33. #define DEAD_SPACE_BOTTOM    10
  34. #define DEAD_SPACE_RIGHT    10
  35. #define    TEXT_RECT_WIDTH        405
  36. #define    TEXT_RECT_HEIGHT    250
  37. #define    BUTTON_WIDTH        60
  38. #define    BUTTON_HEIGHT        60
  39.  
  40. #define MAX_MAIN_TOPICS        4
  41. #define    MAX_SUB_TOPICS        5
  42.  
  43. #define MAIN_TOPIC_ID        600
  44. #define FIRST_SUB_TOPIC_ID    610
  45.  
  46. #define theWindowWidth (boundsRect.right-boundsRect.left)
  47. #define theWindowHeight (boundsRect.bottom-boundsRect.top)
  48. #define CorrectTime 1
  49. #define SCROLL_BOX_SIZE        20
  50.  
  51. typedef unsigned char    **CharHandle;
  52.  
  53. typedef struct
  54. {
  55.     long            offset;
  56.     short            lineHeight;
  57.     short            fontDescent;
  58.     short            fontNum;
  59.     unsigned char    fontStyle;
  60.     unsigned char    unused1;
  61.     short            fontSize;
  62.     short            unused2;
  63.     short            unused3;
  64.     short            unused4;
  65. } OneStyle;
  66.  
  67. typedef struct
  68. {
  69.     short        numStyles;
  70.     OneStyle    theStyle[31];
  71. } StylRec, *StylPtr, **StylHandle;
  72.  
  73. enum
  74. {
  75.     kLeft=0,
  76.     kCenter
  77. };
  78.  
  79. short            gNumMainTopics;
  80. short            gNumSubTopics[MAX_MAIN_TOPICS];
  81.  
  82. CIconHandle        gMainTopicIconColor[MAX_MAIN_TOPICS];
  83. Handle            gMainTopicIconBW[MAX_MAIN_TOPICS];
  84. Str31            gMainTopicTitle[MAX_MAIN_TOPICS];
  85. Rect            gMainTopicRect[MAX_MAIN_TOPICS];
  86.  
  87. CIconHandle        gSubTopicIconColor[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  88. Handle            gSubTopicIconBW[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  89. Str31            gSubTopicTitle[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  90. Rect            gSubTopicRect[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  91. short            gSubTopicID[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  92.  
  93. short            gStickyTopic;
  94. short            gStickySubTopic;
  95.  
  96. short            gMainTopicShowing;        /* saved in prefs file */
  97. short            gSubTopicShowing;        /* saved in prefs file */
  98.  
  99. Rect            gTextRect;
  100. CharHandle        gTheText;
  101. StylHandle        gTheStyle;
  102.  
  103. /*-----------------------------------------------------------------------------------*/
  104. /* internal stuff for help.c                                                         */
  105.  
  106. void SetupTheHelpWindow(WindowDataHandle theData);
  107. void ShutdownTheHelpWindow(WindowDataHandle theData);
  108. void InitializeTheHelpWindow(WindowDataHandle theData);
  109. void OpenTheHelpWindow(WindowDataHandle theData);
  110. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed);
  111. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc);
  112. void DrawTheHelpWindow(short theDepth);
  113. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  114.     short theMode, Rect theRect);
  115. void DrawTheShadowBox(Rect theRect);
  116. short ParseRawTitle(Str255 theTitle);
  117. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  118.     Boolean updateNow);
  119. void PushInSubTopic(WindowDataHandle theData);
  120. void PullOutSubTopic(WindowDataHandle theData, short mainTopic);
  121. void HighlightSubTopic(WindowDataHandle theData, short mainTopic, short subTopic,
  122.     Boolean isHighlighted);
  123. void GetTextResources(short mainTopic, short subTopic);
  124. void DisposeTextResources(void);
  125. void FullScrollRight(GrafPtr sourceGrafPtr, GrafPtr destGrafPtr, Rect boundsRect);
  126.  
  127.  
  128. short HelpWindowDispatch(WindowDataHandle theData, short theMessage, unsigned long misc)
  129. {
  130.     unsigned char    theChar;
  131.     Point            thePoint;
  132.     short            theDepth;
  133.     
  134.     switch (theMessage)
  135.     {
  136.         case kUpdate:
  137.             theDepth=misc&0x7fff;
  138.             DrawTheHelpWindow(theDepth);
  139.             return kSuccess;
  140.             break;
  141.         case kKeydown:
  142.             theChar=misc&charCodeMask;
  143.             KeyPressedInHelpWindow(theData, theChar);
  144.             return kSuccess;
  145.             break;
  146.         case kMousedown:
  147.             thePoint.h=(misc>>16)&0x7fff;
  148.             thePoint.v=misc&0x7fff;
  149.             MouseClickedInHelpWindow(theData, thePoint);
  150.             return kSuccess;
  151.             break;
  152.         case kOpen:
  153.             OpenTheHelpWindow(theData);
  154.             return kSuccess;
  155.             break;
  156.         case kInitialize:
  157.             InitializeTheHelpWindow(theData);
  158.             return kSuccess;
  159.             break;
  160.         case kStartup:
  161.             SetupTheHelpWindow(theData);
  162.             return kSuccess;
  163.             break;
  164.         case kShutdown:
  165.             ShutdownTheHelpWindow(theData);
  166.             return kSuccess;
  167.             break;
  168.     }
  169.     
  170.     return kFailure;        /* revert to default processing for all other messages */
  171. }
  172.  
  173. void SetupTheHelpWindow(WindowDataHandle theData)
  174. {
  175.     short            i,j;
  176.     unsigned char    *helpStr="\pHelp";
  177.     Handle            temp;
  178.     short            iconID;
  179.     short            centeringOffset;
  180.     
  181.     temp=GetResource('STR#', MAIN_TOPIC_ID);
  182.     gNumMainTopics=**((short**)temp);
  183.     ReleaseResource(temp);
  184.     for (i=0; i<gNumMainTopics; i++)
  185.     {
  186.         temp=GetResource('STR#', FIRST_SUB_TOPIC_ID+i);
  187.         gNumSubTopics[i]=**((short**)temp);
  188.         ReleaseResource(temp);
  189.     }
  190.     centeringOffset=(DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+DEAD_SPACE_BOTTOM-
  191.         (gNumMainTopics*BUTTON_HEIGHT))/2;
  192.     for (i=0; i<gNumMainTopics; i++)
  193.     {
  194.         GetIndString(gMainTopicTitle[i], MAIN_TOPIC_ID, i+1);
  195.         iconID=ParseRawTitle(gMainTopicTitle[i]);
  196.         if (gHasColorQD)
  197.             gMainTopicIconColor[i]=GetCIcon(iconID);
  198.         gMainTopicIconBW[i]=GetIcon(iconID);
  199.         SetRect(&gMainTopicRect[i], DEAD_SPACE_LEFT, centeringOffset+BUTTON_HEIGHT*i,
  200.             DEAD_SPACE_LEFT+BUTTON_WIDTH, centeringOffset+BUTTON_HEIGHT*(i+1));
  201.         
  202.         for (j=0; j<gNumSubTopics[i]; j++)
  203.         {
  204.             GetIndString(gSubTopicTitle[i][j], FIRST_SUB_TOPIC_ID+i, j+1);
  205.             iconID=ParseRawTitle(gSubTopicTitle[i][j]);
  206.             gSubTopicID[i][j]=iconID;
  207.             if (gHasColorQD)
  208.                 gSubTopicIconColor[i][j]=GetCIcon(iconID);
  209.             gSubTopicIconBW[i][j]=GetIcon(iconID);
  210.             SetRect(&gSubTopicRect[i][j], DEAD_SPACE_LEFT+BUTTON_WIDTH*(j+1),
  211.                 centeringOffset+BUTTON_HEIGHT*i, DEAD_SPACE_LEFT+BUTTON_WIDTH*(j+2),
  212.                 centeringOffset+BUTTON_HEIGHT*(i+1));
  213.         }
  214.     }
  215.     
  216.     gTheText=gTheStyle=0L;
  217.     GoToPage(0L, gMainTopicShowing, gSubTopicShowing, FALSE);
  218.     
  219.     SetRect(&gTextRect, DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT, DEAD_SPACE_TOP,
  220.         DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+TEXT_RECT_WIDTH,
  221.         DEAD_SPACE_TOP+TEXT_RECT_HEIGHT);
  222.     
  223.     (**theData).maxDepth=8;
  224.     (**theData).windowWidth=DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  225.         TEXT_RECT_WIDTH+DEAD_SPACE_RIGHT;
  226.     (**theData).windowHeight=DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+DEAD_SPACE_BOTTOM;
  227.     (**theData).windowType=noGrowDocProc;    /* document-looking thing */
  228.     (**theData).hasCloseBox=TRUE;
  229.     (**theData).windowBounds.top=50;
  230.     (**theData).windowBounds.left=6;
  231.     Mymemcpy((Ptr)((**(gTheWindowData[kHelp])).windowTitle), (Ptr)helpStr, helpStr[0]+1);
  232. }
  233.  
  234. void ShutdownTheHelpWindow(WindowDataHandle theData)
  235. {
  236.     short            i,j;
  237.     
  238.     for (i=0; i<gNumMainTopics; i++)
  239.     {
  240.         if (gHasColorQD)
  241.             DisposeCIcon(gMainTopicIconColor[i]);
  242.         ReleaseResource(gMainTopicIconBW[i]);
  243.         
  244.         for (j=0; j<gNumSubTopics[i]; j++)
  245.         {
  246.             if (gHasColorQD)
  247.                 DisposeCIcon(gSubTopicIconColor[i][j]);
  248.             ReleaseResource(gSubTopicIconColor[i][j]);
  249.         }
  250.     }
  251.     DisposeTextResources();
  252. }
  253.  
  254. void InitializeTheHelpWindow(WindowDataHandle theData)
  255. {
  256.     (**theData).initialTopLeft.v=(**theData).windowBounds.top-9;
  257.     (**theData).initialTopLeft.h=(**theData).windowBounds.left;
  258.     gStickyTopic=-1;
  259. }
  260.  
  261. void OpenTheHelpWindow(WindowDataHandle theData)
  262. {
  263.     (**theData).offscreenNeedsUpdate=TRUE;
  264. }
  265.  
  266. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed)
  267. {
  268.     short            oldTopic;
  269.     
  270.     ObscureCursor();
  271.     
  272.     switch (keyPressed)
  273.     {
  274.         case 0x1d:                                        /* right arrow */
  275.             if (gStickyTopic==-1)
  276.             {
  277.                 gSubTopicShowing++;
  278.                 if (gSubTopicShowing>=gNumSubTopics[gMainTopicShowing])
  279.                 {
  280.                     gSubTopicShowing=0;
  281.                     gMainTopicShowing++;
  282.                     if (gMainTopicShowing>=gNumMainTopics)
  283.                         gMainTopicShowing=0;
  284.                 }
  285.                 GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  286.             }
  287.             else
  288.             {
  289.                 if (gStickySubTopic!=-1)
  290.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  291.                 gStickySubTopic++;
  292.                 if (gStickySubTopic>=gNumSubTopics[gStickyTopic])
  293.                     gStickySubTopic=0;
  294.                 HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, TRUE);
  295.             }
  296.             break;
  297.         case 0x1c:                                        /* left arrow */
  298.             if (gStickyTopic==-1)
  299.             {
  300.                 gSubTopicShowing--;
  301.                 if (gSubTopicShowing<0)
  302.                 {
  303.                     gMainTopicShowing--;
  304.                     if (gMainTopicShowing<0)
  305.                         gMainTopicShowing=gNumMainTopics-1;
  306.                     gSubTopicShowing=gNumSubTopics[gMainTopicShowing]-1;
  307.                 }
  308.                 GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  309.             }
  310.             else
  311.             {
  312.                 if (gStickySubTopic!=-1)
  313.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  314.                 gStickySubTopic--;
  315.                 if (gStickySubTopic<0)
  316.                     gStickySubTopic=gNumSubTopics[gStickyTopic]-1;
  317.                 HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, TRUE);
  318.             }
  319.             break;
  320.         case 0x1e:                                        /* up arrow */
  321.             if (gStickyTopic!=-1)
  322.             {
  323.                 oldTopic=gStickyTopic;
  324.                 PushInSubTopic(theData);
  325.                 gStickyTopic=oldTopic-1;
  326.                 if (gStickyTopic<0)
  327.                     gStickyTopic=gNumMainTopics-1;
  328.             }
  329.             else gStickyTopic=gNumMainTopics-1;
  330.             
  331.             PullOutSubTopic(theData, gStickyTopic);
  332.             break;
  333.         case 0x1f:                                        /* down arrow */
  334.             if (gStickyTopic!=-1)
  335.             {
  336.                 oldTopic=gStickyTopic;
  337.                 PushInSubTopic(theData);
  338.                 gStickyTopic=oldTopic+1;
  339.                 if (gStickyTopic>=gNumMainTopics)
  340.                     gStickyTopic=0;
  341.             }
  342.             else gStickyTopic=0;
  343.             
  344.             PullOutSubTopic(theData, gStickyTopic);
  345.             break;
  346.         case 0x1b:                                        /* escape key */
  347.             if (gStickyTopic!=-1)
  348.                 PushInSubTopic(theData);
  349.             else CloseTheWindow(theData);
  350.             break;
  351.         case 0x03:
  352.         case 0x0d:
  353.             if (gStickyTopic==-1)
  354.             {
  355.                 gStickyTopic=gMainTopicShowing;
  356.                 PullOutSubTopic(theData, gStickyTopic);
  357.             }
  358.             else
  359.             {
  360.                 if (gStickySubTopic!=-1)
  361.                 {
  362.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  363.                     GoToPage(theData, gStickyTopic, gStickySubTopic, TRUE);
  364.                 }
  365.                 else PushInSubTopic(theData);
  366.             }
  367.             break;
  368.     }
  369. }
  370.  
  371. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc)
  372. {
  373.     short            newTopic;
  374.     Boolean            isColor;
  375.     short            i;
  376.     
  377.     isColor=((**theData).windowDepth>2);
  378.     newTopic=-1;
  379.     
  380.     for (i=0; i<gNumMainTopics; i++)
  381.     {
  382.         if (PtInRect(mouseLoc, &gMainTopicRect[i]))
  383.         {
  384.             newTopic=i;
  385.             i=gNumMainTopics;
  386.         }
  387.     }
  388.     
  389.     if (newTopic!=-1)
  390.     {
  391.         if (newTopic==gStickyTopic)
  392.             PushInSubTopic(theData);
  393.         else
  394.         {
  395.             if (gStickyTopic!=-1)
  396.                 PushInSubTopic(theData);
  397.             PullOutSubTopic(theData, newTopic);
  398.             gStickyTopic=newTopic;
  399.         }
  400.     }
  401.     
  402.     if ((gStickyTopic!=-1) && (newTopic==-1))
  403.     {
  404.         for (i=0; i<gNumSubTopics[gStickyTopic]; i++)
  405.         {
  406.             if (PtInRect(mouseLoc, &gSubTopicRect[gStickyTopic][i]))
  407.             {
  408.                 if (gStickySubTopic!=-1)
  409.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  410.                 gStickySubTopic=-1;
  411.                 
  412.                 if (Track3DButton(&gSubTopicRect[gStickyTopic][i],
  413.                     gSubTopicTitle[gStickyTopic][i], isColor ?
  414.                     (Handle)gSubTopicIconColor[gStickyTopic][i] :
  415.                     gSubTopicIconBW[gStickyTopic][i], (**theData).windowDepth))
  416.                 {
  417.                     newTopic=i;
  418.                     i=gNumSubTopics[gStickyTopic];
  419.                 }
  420.             }
  421.         }
  422.         if (newTopic!=-1)
  423.             GoToPage(theData, gStickyTopic, newTopic, TRUE);
  424.         else
  425.             PushInSubTopic(theData);
  426.     }
  427. }
  428.  
  429. void DrawTheHelpWindow(short theDepth)
  430. {
  431.     GrafPtr            curPort;
  432.     short            i,j;
  433.     Boolean            isColor;
  434.     Rect            tempRect;
  435.     
  436.     isColor=(theDepth>2);
  437.     
  438.     GetPort(&curPort);
  439.     EraseRect(&(curPort->portRect));
  440.     
  441.     DrawTheShadowBox(gTextRect);
  442.     if (gTheText!=0L)
  443.     {
  444.         tempRect=gTextRect;
  445.         InsetRect(&tempRect, 8, 4);
  446.         DrawTheText(gTheText, gTheStyle, kLeft, srcOr, tempRect);
  447.     }
  448.     
  449.     for (i=0; i<gNumMainTopics; i++)
  450.     {
  451.         Draw3DButton(&gMainTopicRect[i], gMainTopicTitle[i],
  452.             isColor ? (Handle)gMainTopicIconColor[i] : gMainTopicIconBW[i],
  453.             theDepth, (i==gStickyTopic));
  454.         if (i==gStickyTopic)
  455.         {
  456.             for (j=0; j<gNumSubTopics[i]; j++)
  457.             {
  458.                 Draw3DButton(&gSubTopicRect[i][j], gSubTopicTitle[i][j],
  459.                 isColor ? (Handle)gSubTopicIconColor[i][j] : gSubTopicIconBW[i][j],
  460.                 theDepth, (j==gStickySubTopic));
  461.             }
  462.         }
  463.     }
  464. }
  465.  
  466. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  467.     short theMode, Rect theRect)
  468. {
  469.     short            i, numStyles;
  470.     long            textPos;
  471.     long            maxOffset;
  472.     Str255            thisLine;
  473.     Boolean            notDoneYet;
  474.     unsigned char    thisChar;
  475.     short            theRow, theCol;
  476.     unsigned char    lastEnd, thisEnd;
  477.     Boolean            overRun;
  478.     
  479.     numStyles=(**theStyleHandle).numStyles;
  480.     textPos=0L;
  481.     theRow=theRect.top+(**theStyleHandle).theStyle[0].fontDescent+1;
  482.     theCol=theRect.left;
  483.     thisLine[0]=0x00;
  484.     lastEnd=0;
  485.     for (i=0; i<numStyles; i++)
  486.     {
  487.         if (i==numStyles-1)
  488.             maxOffset=GetHandleSize(theText);
  489.         else
  490.             maxOffset=(**theStyleHandle).theStyle[i+1].offset;
  491.         
  492.         TextFont((**theStyleHandle).theStyle[i].fontNum);
  493.         TextFace((**theStyleHandle).theStyle[i].fontStyle);
  494.         TextSize((**theStyleHandle).theStyle[i].fontSize);
  495.         TextMode(theMode);
  496.         
  497.         while (textPos<maxOffset)
  498.         {
  499.             notDoneYet=TRUE;
  500.             while ((textPos<maxOffset) && (notDoneYet))
  501.             {
  502.                 thisChar=thisLine[++thisLine[0]]=(*theText)[textPos++];
  503.                 notDoneYet=((thisChar!=' ') && (thisChar!=0x0d));
  504.             }
  505.             
  506.             thisEnd=thisLine[0];
  507.             overRun=(theRect.right-theCol<=StringWidth(thisLine));
  508.             
  509.             if ((overRun) || (thisChar==0x0d) || (textPos==maxOffset))
  510.             {
  511.                 if (overRun)
  512.                     thisLine[0]=lastEnd;
  513.                 if (theJust==kCenter)
  514.                     MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  515.                             theCol, theRow);
  516.                 else
  517.                     MoveTo(theCol, theRow);
  518.                 theCol+=StringWidth(thisLine);
  519.                 DrawString(thisLine);
  520.                 if (overRun)
  521.                 {
  522.                     BlockMove(&thisLine[lastEnd+1], &thisLine[1], thisEnd-lastEnd+1);
  523.                     if (thisEnd>=lastEnd)
  524.                     {
  525.                         thisLine[0]=thisEnd-lastEnd-1;
  526.                         textPos--;
  527.                     }
  528.                     else
  529.                         thisEnd=thisLine[0]=0x00;
  530.                 }
  531.                 else thisLine[0]=0x00;
  532.                 if ((overRun) || (thisChar==0x0d))
  533.                 {
  534.                     theRow+=(**theStyleHandle).theStyle[i].lineHeight;
  535.                     theCol=theRect.left;
  536.                 }
  537.             }
  538.             
  539.             lastEnd=thisEnd;
  540.         }
  541.         
  542.         if (thisLine[0]!=0x00)
  543.         {
  544.             if (theJust==kCenter)
  545.                 MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  546.                         theCol, theRow);
  547.             else
  548.                 MoveTo(theCol, theRow);
  549.             theCol+=StringWidth(thisLine);
  550.             DrawString(thisLine);
  551.             thisLine[0]=0x00;
  552.         }
  553.     }
  554.     TextMode(srcOr);
  555. }
  556.  
  557. void DrawTheShadowBox(Rect theRect)
  558. {
  559.     theRect.right-=2;
  560.     theRect.bottom-=2;
  561.     FrameRect(&theRect);
  562.     MoveTo(theRect.left+3, theRect.bottom+1);
  563.     Line(theRect.right-theRect.left-2, 0);
  564.     Line(0, -theRect.bottom+theRect.top+3);
  565.     MoveTo(theRect.left+3, theRect.bottom);
  566.     Line(theRect.right-theRect.left-3, 0);
  567.     Line(0, -theRect.bottom+theRect.top+4);
  568. }
  569.  
  570. short ParseRawTitle(Str255 theTitle)
  571. {
  572.     Str255            numStr;
  573.     unsigned long    result;
  574.     
  575.     numStr[0]=0x00;
  576.     while ((numStr[numStr[0]]=theTitle[++numStr[0]])!=' ') {}
  577.     theTitle[0]-=numStr[0];
  578.     Mymemcpy(&theTitle[1], &theTitle[numStr[0]+1], theTitle[0]);
  579.     numStr[0]--;
  580.     StringToNum(numStr, &result);
  581.     return result;
  582. }
  583.  
  584. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  585.     Boolean updateNow)
  586. {
  587.     DisposeTextResources();
  588.     GetTextResources(mainTopic, subTopic);
  589.     gMainTopicShowing=mainTopic;
  590.     gSubTopicShowing=subTopic;
  591.     gStickyTopic=gStickySubTopic=-1;
  592.     if (updateNow)
  593.     {
  594.         (**theData).offscreenNeedsUpdate=TRUE;
  595.         UpdateTheWindow(theData);
  596.     }
  597. }
  598.  
  599. void PushInSubTopic(WindowDataHandle theData)
  600. {
  601.     gStickyTopic=-1;
  602.     (**theData).offscreenNeedsUpdate=TRUE;
  603.     UpdateTheWindow(theData);
  604. }
  605.  
  606. void PullOutSubTopic(WindowDataHandle theData, short mainTopic)
  607. {
  608.     short            i;
  609.     short            theDepth;
  610.     Boolean            isColor;
  611.     Rect            tempRect;
  612.     
  613.     gStickySubTopic=-1;
  614.     
  615.     isColor=(theDepth=(**theData).windowDepth)>2;
  616.     
  617.     SetPortToOffscreen(theData);
  618.     for (i=0; i<gNumSubTopics[mainTopic]; i++)
  619.     {
  620.         Draw3DButton(&gSubTopicRect[mainTopic][i], gSubTopicTitle[mainTopic][i],
  621.         isColor ? (Handle)gSubTopicIconColor[mainTopic][i] :
  622.         gSubTopicIconBW[mainTopic][i], theDepth, FALSE);
  623.     }
  624.     RestorePortToScreen(theData);
  625.  
  626.     Draw3DButton(&gMainTopicRect[mainTopic], gMainTopicTitle[mainTopic],
  627.         isColor ? (Handle)gMainTopicIconColor[mainTopic] :
  628.         gMainTopicIconBW[mainTopic], theDepth, TRUE);
  629.     
  630.     tempRect=gSubTopicRect[mainTopic][0];
  631.     tempRect.right=gSubTopicRect[mainTopic][gNumSubTopics[mainTopic]-1].right;
  632.     FullScrollRight(GetOffscreenGrafPtr(theData), GetWindowGrafPtr(theData), tempRect);
  633.     
  634.     (**theData).offscreenNeedsUpdate=TRUE;
  635. }
  636.  
  637. void HighlightSubTopic(WindowDataHandle theData, short mainTopic, short subTopic,
  638.     Boolean isHighlighted)
  639. {
  640.     Draw3DButton(&gSubTopicRect[mainTopic][subTopic], gSubTopicTitle[mainTopic][subTopic],
  641.         ((**theData).windowDepth>2) ? (Handle)gSubTopicIconColor[mainTopic][subTopic] :
  642.         gSubTopicIconBW[mainTopic][subTopic], (**theData).windowDepth, isHighlighted);
  643.     
  644.     (**theData).offscreenNeedsUpdate=TRUE;
  645. }
  646.  
  647. void GetTextResources(short mainTopic, short subTopic)
  648. {
  649.     short            resID;
  650.     
  651.     DisposeTextResources();
  652.     resID=gSubTopicID[mainTopic][subTopic];
  653.     gTheText=GetResource('TEXT', resID);
  654.     gTheStyle=GetResource('styl', resID);
  655. }
  656.  
  657. void DisposeTextResources(void)
  658. {
  659.     if (gTheText!=0L)
  660.         ReleaseResource(gTheText);
  661.     if (gTheStyle!=0L)
  662.         ReleaseResource(gTheStyle);
  663.     gTheText=gTheStyle=0L;
  664. }
  665.  
  666. void FullScrollRight(GrafPtr sourceGrafPtr, GrafPtr destGrafPtr, Rect boundsRect)
  667. {
  668.     Rect            sourceRect, destRect, scrollRect;
  669.     short            BoxSize;
  670.     
  671.     StartTiming();
  672.     
  673.     BoxSize=SCROLL_BOX_SIZE;
  674.     
  675.     destRect=sourceRect=scrollRect=boundsRect;
  676.     destRect.right=destRect.left+BoxSize;
  677.     sourceRect.left=boundsRect.right-BoxSize;
  678.     scrollRect.right=scrollRect.left+2*BoxSize;
  679.     
  680.     CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  681.         &sourceRect, &destRect, 0, 0L);
  682.     
  683.     TimeCorrection(CorrectTime);
  684.     
  685.     while (scrollRect.right<=boundsRect.right)
  686.     {
  687.         StartTiming();
  688.         sourceRect.right-=BoxSize;
  689.         sourceRect.left-=BoxSize;
  690.         ScrollTheRect(&scrollRect, BoxSize, 0, 0L);
  691.         CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  692.             &sourceRect, &destRect, 0, 0L);
  693.         TimeCorrection(CorrectTime);
  694.         scrollRect.right+=BoxSize;
  695.     }
  696.     
  697.     if (scrollRect.right!=boundsRect.right)
  698.         CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  699.             &boundsRect, &boundsRect, 0, 0L);
  700. }
  701.